<?php

namespace pmvc;

use pmvc\util\StringUtil;
use pmvc\ClassLoader;
use Exception;

/**
 * Implementation of the {@link ClassLoader}
 * interface that uses phar files
 */
class PharClassLoader
	extends AbstractClassLoader {

	const PHAR_PREFIX = 'phar://';

	/**
	 * @var array
	 */
	private $classpath = Array();

	/**
	 * Creates the {@link PharClassLoader} and configures
	 * it for loading classes from the given phars.
	 * @param array $phars the phar files that this classloader will use
	 */
	public function __construct($phars=Array()) {
		if (!is_array($phars)) {
			$phars = Array($phars);
		}
		foreach ($phars as $cp) {
			$this->addToClassPath($cp);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	protected function getClasspath() {
		return $this->classpath;
	}

	/**
	 * Adds an phar to the class path.
	 * @param string $phar the phar file
	 * @param array $roots optional roots within the phar
	 */
	public function addToClassPath($phar, $roots=null) {

		// is it a far uri
		$isUri = StringUtil::startsWith($phar, self::PHAR_PREFIX);

		// make sure it's a file
		if (!file_exists($phar)) {
			throw new Exception("phar doesn't exist: $phar");
		} else if (!$isUri && !is_file($phar)) {
			throw new Exception("Path is not a file: $phar");
		}

		// let the phar boot strap
		require_once($phar);

		// turn into URI
		if (!$isUri) {
			$phar = ($this->shouldUseRealpath())
				? realpath($phar) : $phar;
			$phar = self::PHAR_PREFIX.$phar;
		}

		// set classpath root
		$classpathRoot = $phar;

		// make sure we have an array
		if (!isset($roots)) {
			$roots = Array();
		}

		// add roots from a roots folder
		if (!$isUri) {
			$lines = @file_get_contents($phar.'.roots', false);
			if ($lines!==false) {
				foreach (preg_split('/[\r\n]/', $lines) as $line) {
					$line = preg_replace('/[\r\n]/', "", $line);
					if ($line=='/' || $line=='\\') { $line = ""; }
					$roots []= preg_replace('/[\r\n]/', '', $line);
				}
			}
		}

		// add the root of the phar if
		// we don't have any roots definedtr
		if (empty($roots)) {
			$roots []= "";
		}

		// add it to the classpath
		foreach ($roots as $root) {
			array_push($this->classpath, $classpathRoot.DIRECTORY_SEPARATOR.$root);
		}
	}
}

?>